package com.xcity.game.news;

import java.util.Date;
import java.util.EnumMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import com.xcity.db.entity.Mail;
import com.xcity.db.entity.Player;
import com.xcity.db.mapper.MailMapper;
import com.xcity.game.common.MessageConst;
import com.xcity.game.event.GameEvents;
import com.xcity.game.mail.MailService;
import com.xcity.pomelo.PomeloRoute;
import com.xcity.pomelo.request.NewsRequest;
import com.xcity.pomelo.response.HintResponse;
import com.xcity.pomelo.response.NewsResponse;
import com.xcity.util.DBUtils;

import naga.x.App;
import naga.x.event.Event;
import naga.x.event.EventListener;
import naga.x.game.time.TimeUpdater;
import naga.x.net.Session;
import naga.x.net.annotation.OPHandler;
import naga.x.net.impl.pomelo.annotation.PomeloOP;
import naga.x.service.Service;
import naga.x.service.ServiceException;

/**
 * 玩家消息缓存服务
 * @author yang.li
 *
 */
@OPHandler
public class NewsService implements Service, EventListener {

	protected Map<Long, Map<NewsType, LinkedList<News>>> news = new ConcurrentHashMap<Long, Map<NewsType, LinkedList<News>>>(128);
	protected static final int MAIL_VALID_TIME = 10 * 24 * 60 * 60 * 1000;
	
	@Override
	public void startup() throws ServiceException {
		App.getApp().getEventManager().register(this);
	}

	@Override
	public void shutdown() throws ServiceException {
	}

	@Override
	public String getId() {
		return getClass().getName();
	}

	@Override
	public int[] getEventTypes() {
		return new int[] { GameEvents.EVENT_PLAYER_LOGIN, GameEvents.EVENT_PLAYER_LOGOUT };
	}

	@Override
	public void handleEvent(Event event) {
		switch (event.getType()) {
			case GameEvents.EVENT_PLAYER_LOGIN:
				playerLogin(event.getParameter());
				break;
			case GameEvents.EVENT_PLAYER_LOGOUT:
				playerLogout(event.getParameter());
				break;
		}
	}
	
	protected void playerLogin(Player player) {
		App.getApp().getThreadPool().execute(new Runnable() {
			@Override
			public void run() {
				Map<String, Object> params = DBUtils.wrapParams("destId", player.getId(), "type", Mail.TYPE_PVP_MSG);
				List<Mail> mails = DBUtils.findLimit(MailMapper.class, 0, NewsType.PVP_RESULT.capacity, params);
				for (int i = mails != null ? mails.size() - 1 : -1; i >= 0; i--) {
					Mail m = mails.get(i);
					add(player, NewsType.PVP_RESULT, m.getContent());
				}
			}
		});
	}
	
	protected void playerLogout(Player player) {
		news.remove(player.getId());
	}
	
	public void add(Player player, NewsType type, String content) {
		LinkedList<News> list = getNews(player, type, true);
		if (list.size() >= type.capacity) {
			list.removeFirst();
		}
		list.add(new News(type, content));
	}
	
	public void send(Player player, String title, String content) {
		send(player, NewsType.PVP_RESULT, title, content);
	}
	
	public void send(Player player, NewsType type, String title, String content) {
		Mail mail = new Mail(
				Mail.TYPE_PVP_MSG, -1, player.getId(),
				title, content, null,
				new Date(TimeUpdater.getInstance().now()),
				new Date(TimeUpdater.getInstance().now() + MAIL_VALID_TIME),
				Mail.STATE_UNREAD);
		App.getApp().getServiceManager().get(MailService.class).sendMail(mail);
		if (player.isOnline()) {
			add(player, type, content);
		}
	}
	
	protected LinkedList<News> getNews(Player player, NewsType type) {
		return getNews(player, type, false);
	}
	
	protected LinkedList<News> getNews(Player player, NewsType type, boolean createIfNull) {
		return getNews(player.getId(), type, createIfNull);
	}
	
	protected LinkedList<News> getNews(long playerId, NewsType type, boolean createIfNull) {
		Long playerIdObj = Long.valueOf(playerId);
		Map<NewsType, LinkedList<News>> map = news.get(playerIdObj);
		if (map == null) {
			if (!createIfNull) {
				return null;
			}
			map = new EnumMap<NewsType, LinkedList<News>>(NewsType.class);
			news.put(playerIdObj, map);
		}
		LinkedList<News> list = map.get(type);
		if (list == null) {
			if (!createIfNull) {
				return null;
			}
			list = new LinkedList<News>();
			map.put(type, list);
		}
		return list;
	}

	@PomeloOP(PomeloRoute.NEWS)
	protected void requestNews(Session session, NewsRequest req) {
		NewsType type = req.getType();
		if (type == null) {
			session.send(new HintResponse(req.getSerial(), MessageConst.ILLEGAL_OPERATION));
			return;
		}
		Player player = session.getClient();
		List<News> list = getNews(player, type);
		session.send(new NewsResponse(req.getSerial(), list));
	}
	
}
